//-
// ==========================================================================
// Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All 
// rights reserved.
//
// The coded instructions, statements, computer programs, and/or related 
// material (collectively the "Data") in these files contain unpublished 
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its 
// licensors, which is protected by U.S. and Canadian federal copyright 
// law and by international treaties.
//
// The Data is provided for use exclusively by You. You have the right 
// to use, modify, and incorporate this Data into other products for 
// purposes authorized by the Autodesk software license agreement, 
// without fee.
//
// The copyright notices in the Software and this entire statement, 
// including the above license grant, this restriction and the 
// following disclaimer, must be included in all copies of the 
// Software, in whole or in part, and all derivative works of 
// the Software, unless such copies or derivative works are solely 
// in the form of machine-executable object code generated by a 
// source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. 
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED 
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
// PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR 
// TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS 
// BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 
// DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK 
// AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY 
// OR PROBABILITY OF SUCH DAMAGES.
//
// ==========================================================================
//+

///////////////////////////////////////////////////////////////////
//
// DESCRIPTION: 
//		This is an example of using the built in texture cache for drawing.
//
///////////////////////////////////////////////////////////////////

#ifdef WIN32
#pragma warning( disable : 4786 )		// Disable STL warnings.
#endif

#include <maya/MIOStream.h>
#include <maya/MString.h>
#include <maya/MPlug.h>
#include <maya/MFnPlugin.h>
#include <maya/MPxHwShaderNode.h>
#include <maya/MFnMesh.h>

#if MAYA_API_VERSION >= 800
	#include <maya/MHwTextureManager.h>
	#include <maya/MImageFileInfo.h>
#endif

#if defined(OSMac_MachO_)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif

class hwManagedTextureShader : public MPxHwShaderNode
{
	public:
                    hwManagedTextureShader();
    virtual         ~hwManagedTextureShader();

	virtual void    postConstructor();

	virtual MStatus	glBind(const MDagPath& shapePath);
	virtual MStatus	glUnbind(const MDagPath& shapePath);
	virtual MStatus	glGeometry( const MDagPath&,
                              int prim,
							  unsigned int writable,
							  int indexCount,
							  const unsigned int * indexArray,
							  int vertexCount,
							  const int * vertexIDs,
							  const float * vertexArray,
							  int normalCount,
							  const float ** normalArrays,
							  int colorCount,
							  const float ** colorArrays,
							  int texCoordCount,
							  const float ** texCoordArrays);

	virtual int		texCoordsPerVertex();
	virtual int		normalsPerVertex();
	virtual bool	supportsBatching() const;

    static  void *  creator();
    static  MStatus initialize();

	GLboolean lightingOn;
	bool boundTexture;

    static  MTypeId id;
};

// This ID provided by Maya. Do not change.
MTypeId hwManagedTextureShader::id( 0x81033 );

void hwManagedTextureShader::postConstructor( )
{
	setMPSafe(false);
}

hwManagedTextureShader::hwManagedTextureShader()
{
}

hwManagedTextureShader::~hwManagedTextureShader()
{
}

void * hwManagedTextureShader::creator()
{
    return new hwManagedTextureShader();
}

MStatus hwManagedTextureShader::initialize()
{
    return MS::kSuccess;
}

/* virtual */
MStatus	
hwManagedTextureShader::glBind(const MDagPath& path)
{
	// ONLY push and pop required attributes performance reasons...
	//
	glPushAttrib(GL_LIGHTING_BIT);

	lightingOn = glIsEnabled(GL_LIGHTING);

	if (lightingOn)
	{
		glEnable(GL_COLOR_MATERIAL);
		glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
	}

	// Base colour is always white
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

	// Bind texture 
#if MAYA_API_VERSION >= 800
	MObject object = path.node();
	MFnMesh mesh(object);
	MString uvSetName("map1");
	MObjectArray textures;

	boundTexture = false;
	MStatus status = mesh.getAssociatedUVSetTextures(uvSetName, textures);
	if (status == MS::kSuccess && textures.length())
	{
		MImageFileInfo::MHwTextureType hwType;
		if (MS::kSuccess == MHwTextureManager::glBind( textures[0], hwType ))
		{
			boundTexture = true;
		}
	}

	if( !boundTexture)
	{
		glDisable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, 0);
	}
#else
	// To get this code branch to compile, replace <change file name here>
	// with an appropriate file name
	static GLuint id = 0;
	if (id == 0)
	{
		MImage fileImage;
		MStatus status = fileImage.readFromFile("<change file name here>");
		glGenTextures(1, &id);
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, id);
		GLuint width, height;
        fileImage.getSize( width, height);
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, fileImage.pixels());
	}
	else
	{
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, id);
	}
	boundTexture = true;

#endif
	if( boundTexture)
	{
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}
	glEnableClientState(GL_VERTEX_ARRAY);

	return MS::kSuccess;
}

/* virtual */
MStatus	
hwManagedTextureShader::glUnbind(const MDagPath& shapePath)
{
	// Cleanup GL state, without using pushing and popping attributes
	//
	glDisableClientState(GL_VERTEX_ARRAY);
	if (lightingOn)
	{
		glDisable(GL_COLOR_MATERIAL);
		glDisableClientState(GL_NORMAL_ARRAY);
	}
	if (boundTexture)
	{
		glDisableClientState( GL_TEXTURE_COORD_ARRAY );
		glDisable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, 0);
	}

	// ONLY push and pop required attributes performance reasons...
	//
	glPopAttrib();
    return MS::kSuccess;
}

bool
hwManagedTextureShader::supportsBatching() const
{
	return true;
}

/* virtual */
MStatus	hwManagedTextureShader::glGeometry( const MDagPath& path,
                                int prim,
								unsigned int writable,
								int indexCount,
								const unsigned int * indexArray,
								int vertexCount,
								const int * vertexIDs,
								const float * vertexArray,
								int normalCount,
								const float ** normalArrays,
								int colorCount,
								const float ** colorArrays,
								int texCoordCount,
								const float ** texCoordArrays)
{
	glVertexPointer ( 3, GL_FLOAT, 0, &vertexArray[0] );

	if (boundTexture && texCoordCount && texCoordArrays[0] != NULL)
	{
		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		glTexCoordPointer( 2, GL_FLOAT, 0, &texCoordArrays[0][0] );
	}
	else
	{
		glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	}

	if (lightingOn && normalCount && normalArrays[0][0])
	{
		// Don't route normals if we don't need them
		glEnableClientState(GL_NORMAL_ARRAY);
		glNormalPointer ( GL_FLOAT, 0, &normalArrays[0][0] );
	}
	else
	{
		glDisableClientState( GL_NORMAL_ARRAY );
	}

	glDrawElements ( prim, indexCount, GL_UNSIGNED_INT, indexArray );

	return MS::kSuccess;
}

// virtual
int	hwManagedTextureShader::texCoordsPerVertex()
{
	return 1;
}

// virtual
int	hwManagedTextureShader::normalsPerVertex()
{
	return 1;
}



//////////////////////////////////////////////////////////////
MStatus initializePlugin( MObject obj )
{ 
	MStatus   status;

	const MString UserClassify( "shader/surface/utility/" );

	MFnPlugin plugin( obj, PLUGIN_COMPANY, "8.0", "Any");

	status = plugin.registerNode("hwManagedTextureShader",
								 hwManagedTextureShader::id, 
								 hwManagedTextureShader::creator,
								 hwManagedTextureShader::initialize,
								 MPxNode::kHwShaderNode, &UserClassify );
	CHECK_MSTATUS(status);

	return status;
}

MStatus uninitializePlugin( MObject obj )
{
	MStatus   status;
	MFnPlugin plugin( obj );

	status = plugin.deregisterNode( hwManagedTextureShader::id );
	CHECK_MSTATUS(status);

	return status;
}


